// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	12/29/2013 9:10:08 PM				
// -----------------------------

#include "Vector4.h"
#include "Vector3.h"
#include "Vector2.h"
#include "CMath.h"

/* Constants */
const Vector4 Vector4::Zero = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
const Vector4 Vector4::One = Vector4(1.0f, 1.0f, 1.0f, 0.0f);
const Vector4 Vector4::UnitX = Vector4(1.0f, 0.0f, 0.0f, 0.0f);
const Vector4 Vector4::UnitY = Vector4(0.0f, 1.0f, 0.0f, 0.0f);
const Vector4 Vector4::UnitZ = Vector4(0.0f, 0.0f, 1.0f, 0.0f);

/* Constructors */
Vector4::Vector4()
	: x(0.0f)
	, y(0.0f)
	, z(0.0f)
	, w(0.0f)
{
}

Vector4::Vector4(Float X, Float Y, Float Z)
	: x(X)
	, y(Y)
	, z(Z)
	, w(0.0f)
{
}

Vector4::Vector4(Float X, Float Y, Float Z, Float W)
	: x(X)
	, y(Y)
	, z(Z)
	, w(W)
{
}

Vector4::Vector4(Float arr[4])
	: x(arr[0])
	, y(arr[1])
	, z(arr[2])
	, w(arr[3])
{
}

Vector4::Vector4(const Vector4& refVector)
	: x(refVector.x)
	, y(refVector.y)
	, z(refVector.z)
	, w(refVector.w)
{
}

Vector4::Vector4(const Vector3& refVector, Float W)
	: x(refVector.x)
	, y(refVector.y)
	, z(refVector.z)
	, w(W)
{
}

Vector4::Vector4(const Vector2& refVector, Float Z, Float W)
	: x(refVector.x)
	, y(refVector.y)
	, z(Z)
	, w(W)
{
}

Vector4& Vector4::operator=(const Vector4& refVector)
{
	x = refVector.x;
	y = refVector.y;
	z = refVector.z;
	w = refVector.w;
	return (*this);
}


/* Comparison Operators */
Bool Vector4::operator==(const Vector4& refVector) const
{
	return (x == refVector.x) &&
		(y == refVector.y) &&
		(z == refVector.z);
}

Bool Vector4::operator!=(const Vector4& refVector) const
{
	return (x != refVector.x) ||
		(y != refVector.y) ||
		(z != refVector.z);
}

Bool Vector4::operator<(const Vector4& refVector) const
{
	return (x < refVector.x) &&
		(y < refVector.y) &&
		(z < refVector.z);
}

Bool Vector4::operator>(const Vector4& refVector) const
{
	return (x > refVector.x) &&
		(y > refVector.y) &&
		(z > refVector.z);
}

Bool Vector4::operator<=(const Vector4& refVector) const
{
	return (x <= refVector.x) &&
		(y <= refVector.y) &&
		(z <= refVector.z);
}

Bool Vector4::operator>=(const Vector4& refVector) const
{
	return (x >= refVector.x) &&
		(y >= refVector.y) &&
		(z >= refVector.z);
}


/* Mathematical In-Place operators */
Vector4& Vector4::operator+=(const Vector4& refVector)
{
	x += refVector.x;
	y += refVector.y;
	z += refVector.z;
	w += refVector.w;
	return (*this);
}

Vector4& Vector4::operator-=(const Vector4& refVector)
{
	x -= refVector.x;
	y -= refVector.y;
	z -= refVector.z;
	w -= refVector.w;
	return (*this);
}

Vector4& Vector4::operator*=(Float fScalar)
{
	x *= fScalar;
	y *= fScalar;
	z *= fScalar;
	w *= fScalar;
	return (*this);
}

Vector4& Vector4::operator/=(Float fScalar)
{
	x /= fScalar;
	y /= fScalar;
	z /= fScalar;
	w /= fScalar;
	return (*this);
}


/* Mathematical Out-Of-Place Operators */
Vector4 Vector4::operator+(const Vector4& refVector) const
{
	Vector4 tmp(*this);
	tmp += refVector;
	return tmp;
}

Vector4 Vector4::operator-(const Vector4& refVector) const
{
	Vector4 tmp(*this);
	tmp -= refVector;
	return tmp;
}

Vector4 Vector4::operator-() const
{
	return Vector4(-x, -y, -z, w);
}

Vector4 Vector4::operator*(Float fScalar) const
{
	Vector4 tmp(*this);
	tmp *= fScalar;
	return tmp;
}

Vector4 Vector4::operator/(Float fScalar) const
{
	Vector4 tmp(*this);
	tmp /= fScalar;
	return tmp;
}


/* Mathematical Friend Operators */
Vector4 operator*(Float fScalar, const Vector4& refVector)
{
	return (refVector * fScalar);
}


/* Methods */
Float Vector4::Length() const
{
	return Math::Sqrt(x*x + y*y + z*z);
}

Vector4 Vector4::Normalized() const
{
	return ((*this) / this->Length());
}

Vector4	Vector4::CrossProduct(const Vector4& refVector) const
{
	return Vector4((y * refVector.z) - (z * refVector.y),
		(x * refVector.z) - (z * refVector.x),
		(y * refVector.x) - (x * refVector.y),
		0.0f);
}

Float Vector4::DotProduct(const Vector4& refVector) const
{
	return (x * refVector.x) + (y * refVector.y) + (z * refVector.z);
}
void Vector4::AsArray(Float arr[4]) const
{
	arr[0] = x;
	arr[1] = y;
	arr[2] = z;
	arr[3] = w;
}
Vector4 Vector4::Lerp(const Vector4& other, Float alpha) const
{
	return Vector4(Math::Lerp(x, other.x, alpha),
		Math::Lerp(y, other.y, alpha),
		Math::Lerp(z, other.z, alpha),
		Math::Lerp(w, other.w, alpha));
}